"""
游戏界面基类
包含所有游戏模式共用的绘制和交互逻辑
"""

import pygame
import sys
from rules import GobangRules


class BaseGameGUI:
    """五子棋游戏界面基类"""
    
    def __init__(self, board_size=15, cell_size=40):
        """
        初始化游戏界面
        :param board_size: 棋盘大小
        :param cell_size: 每个格子的大小（像素）
        """
        self.board_size = board_size
        self.cell_size = cell_size
        self.margin = 50  # 边距
        
        # 计算窗口大小
        self.window_width = self.cell_size * (board_size - 1) + 2 * self.margin
        self.window_height = self.cell_size * (board_size - 1) + 2 * self.margin + 100
        
        # 初始化Pygame（如果还没初始化）
        if not pygame.get_init():
            pygame.init()
        
        self.screen = pygame.display.set_mode((self.window_width, self.window_height))
        self.clock = pygame.time.Clock()
        
        # 颜色定义
        self.COLOR_BG = (220, 179, 92)  # 棋盘背景色
        self.COLOR_LINE = (0, 0, 0)     # 线条颜色
        self.COLOR_BLACK = (0, 0, 0)    # 黑棋
        self.COLOR_WHITE = (255, 255, 255)  # 白棋
        self.COLOR_TEXT = (0, 0, 0)     # 文字颜色
        self.COLOR_BUTTON = (100, 150, 200)  # 按钮颜色
        self.COLOR_BUTTON_HOVER = (120, 170, 220)  # 按钮悬停颜色
        self.COLOR_MENU = (200, 100, 100)  # 返回菜单按钮颜色
        
        # 字体 - 使用系统中文字体
        try:
            self.font = pygame.font.SysFont('microsoftyahei', 32)
            self.small_font = pygame.font.SysFont('microsoftyahei', 24)
        except:
            try:
                self.font = pygame.font.SysFont('simhei', 32)
                self.small_font = pygame.font.SysFont('simhei', 24)
            except:
                self.font = pygame.font.SysFont('arial', 32)
                self.small_font = pygame.font.SysFont('arial', 24)
        
        # 游戏状态
        self.game_rules = GobangRules(board_size)
        self.mode_name = "五子棋"  # 模式名称（子类可覆盖）
        
        # 按钮
        self.buttons = self.create_buttons()
        
        # 游戏结束对话框拖拽状态
        self.game_over_dialog_pos = None
        self._game_over_dragging = False
        self._game_over_drag_offset = (0, 0)
        
    def create_buttons(self):
        """创建界面按钮"""
        button_y = self.window_height - 80
        buttons = {
            'restart': pygame.Rect(20, button_y, 100, 40),
            'undo': pygame.Rect(130, button_y, 100, 40),
            'menu': pygame.Rect(self.window_width - 120, button_y, 100, 40),
        }
        return buttons
    
    def draw_board(self):
        """绘制棋盘"""
        # 填充背景
        self.screen.fill(self.COLOR_BG)
        
        # 绘制网格线
        for i in range(self.board_size):
            # 横线
            start_x = self.margin
            start_y = self.margin + i * self.cell_size
            end_x = self.margin + (self.board_size - 1) * self.cell_size
            end_y = start_y
            pygame.draw.line(self.screen, self.COLOR_LINE, (start_x, start_y), (end_x, end_y), 2)
            
            # 竖线
            start_x = self.margin + i * self.cell_size
            start_y = self.margin
            end_x = start_x
            end_y = self.margin + (self.board_size - 1) * self.cell_size
            pygame.draw.line(self.screen, self.COLOR_LINE, (start_x, start_y), (end_x, end_y), 2)
        
        # 绘制天元和星位
        star_positions = []
        if self.board_size == 15:
            star_positions = [(3, 3), (3, 11), (11, 3), (11, 11), (7, 7)]
        
        for row, col in star_positions:
            x = self.margin + col * self.cell_size
            y = self.margin + row * self.cell_size
            pygame.draw.circle(self.screen, self.COLOR_LINE, (x, y), 5)
    
    def draw_pieces(self):
        """绘制棋子"""
        board = self.game_rules.board
        for row in range(self.board_size):
            for col in range(self.board_size):
                if board[row][col] != 0:
                    x = self.margin + col * self.cell_size
                    y = self.margin + row * self.cell_size
                    color = self.COLOR_BLACK if board[row][col] == 1 else self.COLOR_WHITE
                    pygame.draw.circle(self.screen, color, (x, y), self.cell_size // 2 - 2)
                    # 白棋加黑边
                    if board[row][col] == 2:
                        pygame.draw.circle(self.screen, self.COLOR_LINE, (x, y), self.cell_size // 2 - 2, 2)
        
        # 标记最后一步
        if self.game_rules.move_history:
            last_row, last_col, _ = self.game_rules.move_history[-1]
            x = self.margin + last_col * self.cell_size
            y = self.margin + last_row * self.cell_size
            pygame.draw.circle(self.screen, (255, 0, 0), (x, y), 5)
    
    def draw_game_over_overlay(self, result_text):
        """
        绘制游戏结束覆盖层（可拖拽）
        :param result_text: 结果文本
        """
        # 创建半透明遮罩
        overlay = pygame.Surface((self.window_width, self.window_height))
        overlay.set_alpha(180)
        overlay.fill((0, 0, 0))
        self.screen.blit(overlay, (0, 0))
        
        # 对话框尺寸与位置
        dialog_width = 500
        dialog_height = 280
        if self.game_over_dialog_pos is None:
            dialog_x = (self.window_width - dialog_width) // 2
            dialog_y = (self.window_height - dialog_height) // 2
            self.game_over_dialog_pos = (dialog_x, dialog_y)
        else:
            dialog_x, dialog_y = self.game_over_dialog_pos
        
        dialog_rect = pygame.Rect(dialog_x, dialog_y, dialog_width, dialog_height)
        self.game_over_dialog_rect = dialog_rect  # 记录供拖拽碰撞使用
        
        pygame.draw.rect(self.screen, (250, 250, 250), dialog_rect, border_radius=15)
        pygame.draw.rect(self.screen, (80, 80, 80), dialog_rect, 3, border_radius=15)
        
        # 绘制结果文本
        try:
            title_font = pygame.font.SysFont('microsoftyahei', 42, bold=True)
            button_font = pygame.font.SysFont('microsoftyahei', 26)
        except:
            try:
                title_font = pygame.font.SysFont('simhei', 42, bold=True)
                button_font = pygame.font.SysFont('simhei', 26)
            except:
                title_font = pygame.font.SysFont('arial', 42, bold=True)
                button_font = pygame.font.SysFont('arial', 26)
        
        # 标题居中到对话框
        title_surface = title_font.render(result_text, True, (50, 50, 50))
        title_rect = title_surface.get_rect(center=(dialog_x + dialog_width // 2, dialog_y + 70))
        self.screen.blit(title_surface, title_rect)
        
        # 按钮相对对话框居中
        button_width = 180
        button_height = 60
        button_spacing = 30
        button_y = dialog_y + 170
        
        restart_rect = pygame.Rect(
            dialog_x + (dialog_width - button_width * 2 - button_spacing) // 2,
            button_y,
            button_width,
            button_height
        )
        menu_rect = pygame.Rect(
            restart_rect.right + button_spacing,
            button_y,
            button_width,
            button_height
        )
        
        mouse_pos = pygame.mouse.get_pos()
        
        # 绘制重新开始按钮
        restart_color = (120, 170, 220) if restart_rect.collidepoint(mouse_pos) else (100, 150, 200)
        pygame.draw.rect(self.screen, restart_color, restart_rect, border_radius=10)
        pygame.draw.rect(self.screen, (80, 80, 80), restart_rect, 2, border_radius=10)
        restart_text = button_font.render('再来一局', True, (255, 255, 255))
        restart_text_rect = restart_text.get_rect(center=restart_rect.center)
        self.screen.blit(restart_text, restart_text_rect)
        
        # 绘制返回菜单按钮
        menu_color = (220, 120, 120) if menu_rect.collidepoint(mouse_pos) else (200, 100, 100)
        pygame.draw.rect(self.screen, menu_color, menu_rect, border_radius=10)
        pygame.draw.rect(self.screen, (80, 80, 80), menu_rect, 2, border_radius=10)
        menu_text = button_font.render('返回菜单', True, (255, 255, 255))
        menu_text_rect = menu_text.get_rect(center=menu_rect.center)
        self.screen.blit(menu_text, menu_text_rect)
        
        return restart_rect, menu_rect
    
    def get_game_result_text(self):
        """
        获取游戏结果文本（子类可覆盖）
        :return: 结果文本
        """
        # 检查是否是禁手
        if hasattr(self.game_rules, 'forbidden_reason') and self.game_rules.forbidden_reason:
            return f"黑棋{self.game_rules.forbidden_reason}，白棋获胜！"
        
        if self.game_rules.winner == 0:
            return "平局！"
        elif self.game_rules.winner == 1:
            return "黑棋获胜！"
        else:
            return "白棋获胜！"
    
    def get_status_text(self):
        """
        获取状态文本（子类可覆盖）
        :return: 状态文本
        """
        if self.game_rules.game_over:
            if self.game_rules.winner == 0:
                return "平局！"
            elif self.game_rules.winner == 1:
                return "黑棋获胜！"
            else:
                return "白棋获胜！"
        else:
            current = "黑棋" if self.game_rules.current_player == 1 else "白棋"
            return f"当前: {current}"
    
    def draw_status(self):
        """绘制游戏状态信息"""
        text = self.get_status_text()
        text_surface = self.font.render(text, True, self.COLOR_TEXT)
        text_rect = text_surface.get_rect(center=(self.window_width // 2, 20))
        self.screen.blit(text_surface, text_rect)
    
    def draw_buttons(self):
        """绘制按钮"""
        mouse_pos = pygame.mouse.get_pos()
        
        button_labels = {
            'restart': '重新开始',
            'undo': '悔棋',
            'menu': '返回菜单',
        }
        
        for name, rect in self.buttons.items():
            # 检查鼠标悬停
            is_hover = rect.collidepoint(mouse_pos)
            
            # 返回菜单按钮使用不同颜色
            if name == 'menu':
                color = (220, 120, 120) if is_hover else self.COLOR_MENU
            else:
                color = self.COLOR_BUTTON_HOVER if is_hover else self.COLOR_BUTTON
            
            pygame.draw.rect(self.screen, color, rect, border_radius=5)
            pygame.draw.rect(self.screen, self.COLOR_LINE, rect, 2, border_radius=5)
            
            # 绘制按钮文字
            text_surface = self.small_font.render(button_labels[name], True, (255, 255, 255))
            text_rect = text_surface.get_rect(center=rect.center)
            self.screen.blit(text_surface, text_rect)
    
    def get_board_position(self, mouse_pos):
        """
        将鼠标位置转换为棋盘坐标
        :param mouse_pos: 鼠标位置 (x, y)
        :return: (row, col) 或 None
        """
        x, y = mouse_pos
        
        # 计算最近的交叉点
        col = round((x - self.margin) / self.cell_size)
        row = round((y - self.margin) / self.cell_size)
        
        # 检查是否在有效范围内
        if 0 <= row < self.board_size and 0 <= col < self.board_size:
            # 检查点击是否足够接近交叉点
            actual_x = self.margin + col * self.cell_size
            actual_y = self.margin + row * self.cell_size
            distance = ((x - actual_x) ** 2 + (y - actual_y) ** 2) ** 0.5
            
            if distance < self.cell_size / 2:
                return (row, col)
        
        return None
    
    def handle_player_move(self, row, col):
        """
        处理玩家落子（子类必须实现）
        :param row: 行坐标
        :param col: 列坐标
        """
        raise NotImplementedError("子类必须实现handle_player_move方法")
    
    def ai_move(self):
        """执行AI落子（子类必须实现）"""
        raise NotImplementedError("子类必须实现ai_move方法")
    
    def undo_move(self):
        """悔棋（子类必须实现）"""
        raise NotImplementedError("子类必须实现undo_move方法")
    
    def restart_game(self):
        """重新开始游戏"""
        self.game_rules.reset()
    
    def draw_confirm_menu_overlay(self):
        """绘制'返回菜单'确认覆盖层，返回(yes_rect, no_rect)"""
        # 半透明遮罩
        overlay = pygame.Surface((self.window_width, self.window_height))
        overlay.set_alpha(160)
        overlay.fill((0, 0, 0))
        self.screen.blit(overlay, (0, 0))

        # 对话框
        dialog_width = 520
        dialog_height = 220
        dialog_x = (self.window_width - dialog_width) // 2
        dialog_y = (self.window_height - dialog_height) // 2
        dialog_rect = pygame.Rect(dialog_x, dialog_y, dialog_width, dialog_height)

        pygame.draw.rect(self.screen, (250, 250, 250), dialog_rect, border_radius=14)
        pygame.draw.rect(self.screen, (80, 80, 80), dialog_rect, 3, border_radius=14)

        # 字体
        try:
            title_font = pygame.font.SysFont('microsoftyahei', 34, bold=True)
            button_font = pygame.font.SysFont('microsoftyahei', 26)
        except:
            try:
                title_font = pygame.font.SysFont('simhei', 34, bold=True)
                button_font = pygame.font.SysFont('simhei', 26)
            except:
                title_font = pygame.font.SysFont('arial', 34, bold=True)
                button_font = pygame.font.SysFont('arial', 26)

        # 文本
        msg = "游戏正在进行，是否返回菜单"
        msg_surface = title_font.render(msg, True, (50, 50, 50))
        msg_rect = msg_surface.get_rect(center=(self.window_width // 2, dialog_y + 70))
        self.screen.blit(msg_surface, msg_rect)

        # 按钮区域
        button_width = 160
        button_height = 56
        spacing = 40
        button_y = dialog_y + 140

        yes_rect = pygame.Rect(
            (self.window_width - button_width * 2 - spacing) // 2,
            button_y,
            button_width,
            button_height
        )
        no_rect = pygame.Rect(
            yes_rect.right + spacing,
            button_y,
            button_width,
            button_height
        )

        mouse_pos = pygame.mouse.get_pos()

        # 是按钮（确认返回）
        yes_color = (220, 120, 120) if yes_rect.collidepoint(mouse_pos) else (200, 100, 100)
        pygame.draw.rect(self.screen, yes_color, yes_rect, border_radius=10)
        pygame.draw.rect(self.screen, (80, 80, 80), yes_rect, 2, border_radius=10)
        yes_text = button_font.render('是', True, (255, 255, 255))
        yes_text_rect = yes_text.get_rect(center=yes_rect.center)
        self.screen.blit(yes_text, yes_text_rect)

        # 否按钮（继续游戏）
        no_color = (120, 170, 220) if no_rect.collidepoint(mouse_pos) else (100, 150, 200)
        pygame.draw.rect(self.screen, no_color, no_rect, border_radius=10)
        pygame.draw.rect(self.screen, (80, 80, 80), no_rect, 2, border_radius=10)
        no_text = button_font.render('否', True, (255, 255, 255))
        no_text_rect = no_text.get_rect(center=no_rect.center)
        self.screen.blit(no_text, no_text_rect)

        return yes_rect, no_rect
    
    def confirm_return_to_menu(self):
        """
        游戏进行中弹出确认框。返回True表示确认返回菜单，False表示继续游戏。
        游戏未开始（无落子）或已结束时直接返回True。
        """
        # 未开始或已结束：直接允许返回
        if self.game_rules.game_over or not self.game_rules.move_history:
            return True

        while True:
            # 先绘制当前局面
            self.draw_board()
            self.draw_pieces()
            self.draw_status()
            self.draw_buttons()

            # 叠加确认覆盖层
            yes_rect, no_rect = self.draw_confirm_menu_overlay()
            pygame.display.flip()

            # 事件处理
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:
                        if yes_rect.collidepoint(event.pos):
                            return True
                        elif no_rect.collidepoint(event.pos):
                            return False

            self.clock.tick(60)
    
    def handle_click(self, pos):
        """
        处理鼠标点击事件
        :param pos: 鼠标位置
        :return: 'menu' 如果点击返回菜单，否则返回 None
        """
        # 检查按钮点击
        for name, rect in self.buttons.items():
            if rect.collidepoint(pos):
                if name == 'restart':
                    self.restart_game()
                elif name == 'undo':
                    self.undo_move()
                elif name == 'menu':
                    return 'menu'
                return None
        
        # 检查棋盘点击
        board_pos = self.get_board_position(pos)
        if board_pos:
            row, col = board_pos
            self.handle_player_move(row, col)
        
        return None
    
    def run(self):
        """运行游戏主循环"""
        running = True
        game_over_shown = False  # 记录是否已显示结束弹框
        
        while running:
            # 绘制界面
            self.draw_board()
            self.draw_pieces()
            self.draw_status()
            self.draw_buttons()
            
            # 检查游戏是否结束
            if self.game_rules.game_over:
                if not game_over_shown:
                    game_over_shown = True
                    # 等待一小段时间让玩家看到最后一步
                    pygame.display.flip()
                    pygame.time.wait(500)
                
                # 绘制游戏结束覆盖层
                result_text = self.get_game_result_text()
                restart_rect, menu_rect = self.draw_game_over_overlay(result_text)
                
                pygame.display.flip()
                
                # 处理覆盖层上的点击/拖拽事件
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        pygame.quit()
                        sys.exit()
                    elif event.type == pygame.MOUSEBUTTONDOWN:
                        if event.button == 1:  # 左键点击
                            mouse_pos = event.pos
                            # 先判断按钮交互
                            if restart_rect.collidepoint(mouse_pos):
                                # 重新开始游戏
                                self.restart_game()
                                game_over_shown = False
                                # 重置对话框位置状态
                                self.game_over_dialog_pos = None
                                self._game_over_dragging = False
                            elif menu_rect.collidepoint(mouse_pos):
                                # 返回主菜单
                                self.game_over_dialog_pos = None
                                self._game_over_dragging = False
                                return 'menu'
                            # 如果点在对话框内，开始拖拽
                            elif self.game_over_dialog_rect.collidepoint(mouse_pos):
                                self._game_over_dragging = True
                                dx = mouse_pos[0] - self.game_over_dialog_rect.x
                                dy = mouse_pos[1] - self.game_over_dialog_rect.y
                                self._game_over_drag_offset = (dx, dy)
                    elif event.type == pygame.MOUSEBUTTONUP:
                        if event.button == 1:
                            self._game_over_dragging = False
                    elif event.type == pygame.MOUSEMOTION:
                        if self._game_over_dragging:
                            mx, my = event.pos
                            dx, dy = self._game_over_drag_offset
                            new_x = mx - dx
                            new_y = my - dy
                            # 约束对话框不超出窗口
                            dialog_w, dialog_h = self.game_over_dialog_rect.size
                            new_x = max(0, min(self.window_width - dialog_w, new_x))
                            new_y = max(0, min(self.window_height - dialog_h, new_y))
                            self.game_over_dialog_pos = (new_x, new_y)
                
                self.clock.tick(60)
                continue
            
            # 游戏未结束时的正常处理
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:  # 左键点击
                        # 如果AI正在思考，忽略点击事件
                        if hasattr(self, 'ai_thinking') and self.ai_thinking:
                            continue
                        
                        result = self.handle_click(event.pos)
                        if result == 'menu':
                            # 弹出确认返回菜单
                            if self.confirm_return_to_menu():
                                return 'menu'
                            # 用户选择否，继续当前对局
            
            # AI思考和落子
            self.ai_move()
            
            pygame.display.flip()
            self.clock.tick(60)  # 60 FPS
        
        return None
